/*
  a mulity column tree control. Dirived from CTree so have the same interface.
  the main problems to resolve
    1. custom draw tree's subitems
    2. mouse hit test for subitems
    3. in place edit
  
  I had try to add hscroll, but there are some problems when horizontal size change
    1. when the vscroll bar appear or disappear. 
    2. when item expanding. ( I can't filter these notify, 
		and can only use these messages(notify reflect) when parent not use them)
  It is not necessary to use hscroll in dialog for the width of MCTree is fixed!
  So I remove the hscroll related code!!!

    $Id$
    
*/

#pragma once

//
// MCTree control special defines
//
#define MCT_CLMN_EDITABLE	(1<<0)		// whether the column is editable
#define MCTVN_DELETEITEM TVN_LAST+1		// the parent can't recieve the TVN_DELETEITEM notify, instead MCTree send this notify

#include <vector>

class CInPlcEdit;


// CMCTreeCtrl
class CMCTreeCtrl : public CTreeCtrl
{
private:
	DECLARE_DYNAMIC(CMCTreeCtrl)

public:
	CMCTreeCtrl();
	virtual ~CMCTreeCtrl();

public:
	//!!!must first call this function, and can only call once!!!
	BOOL SetDimension(DWORD dwDimension);

//
// column
public:
	BOOL InsertMCTClmn(int nPos, WORD wWidth, WORD wId, DWORD dwFlag=0);
	BOOL DeleteMCTClmn(int nPos);
	BOOL GetMCTClmnInfo(int nPos, WORD* pwWidth=NULL, WORD* pwId=NULL, DWORD* pdwFlag=NULL);
	BOOL EditMCTClmn(int nPos, WORD wWidth, WORD wId, DWORD dwFlag=0);
	BOOL EditMCTClmnWidth(int nPos, WORD wWidth);
   
//
// items
public:
	HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct, DWORD_PTR dwPara=NULL);
	HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage,	int nSelectedImage,	HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST, DWORD_PTR dwPara=NULL);
	BOOL SetSubItem(HTREEITEM hItem, DWORD dwSubId, TCHAR* pStr);
	DWORD SetSubItemS(HTREEITEM hItem, DWORD dwSize, DWORD *pdwSubIds, CString *pcstrS);
	BOOL GetSubItem(HTREEITEM hItem, DWORD dwSubId, TCHAR* pStr, DWORD* pdwLen) const;
//	BOOL DeleteItem(HTREEITEM hItem);
	BOOL DeleteSubItems(HTREEITEM hItem);
	BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData);
	DWORD_PTR GetItemData(HTREEITEM hItem);

//
// iterator
//
public:
	enum FOREACH_TYPE{FOREACH_TYPE_DEEP, FOREACH_TYPE_PREV};
	typedef BOOL (*pfnForEachMCTreeItem)(VOID* pv, HTREEITEM hitem);
	BOOL ForEach(FOREACH_TYPE type, pfnForEachMCTreeItem pfn, VOID* pv, HTREEITEM hitem=TVI_ROOT);
	BOOL ForEachAfter(FOREACH_TYPE type, pfnForEachMCTreeItem pfn, VOID* pv, HTREEITEM hItem, HTREEITEM hItemAfter);
	BOOL ForEachAfter(FOREACH_TYPE type, pfnForEachMCTreeItem pfn, VOID* pv, HTREEITEM hItem, std::vector<HTREEITEM>* pvectHitem);

// in TVN_BEGINLABELEDIT TVN_ENDLABELEDIT Notification,
// TVITEM.mask use this bit to indicate the TVITEM.iImage is edit subid
#define MCTVIF_EDITSUBID	(1<<31)	
public:
	BOOL GetEditSubId(DWORD* pdwSubId);
	CEdit* GetEditControl( ){return reinterpret_cast<CEdit*>(m_pcEdit);};

//
// clipboard operations
public:
	void DoPaste();
	void DoCopy();
	void DoCut();

//
// message handles
//
protected:
	DECLARE_MESSAGE_MAP()

//
//  use presubclass(not OnCreate or PrevCreate) to modify some property,
//  we may not receive WM_CREATE for a dialog.
	virtual void PreSubclassWindow();
//
// do some fileters
// filter the mouse message and modify the coordinate for tree control
protected:
	virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);
	virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);

//
// custom draw
public:
	afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);

//
// mouse related functions
public:
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

public:
	afx_msg virtual void OnTvnDeleteitem(NMHDR *pNMHDR, LRESULT *pResult);

private:
	afx_msg void OnEnKillfocus();

//
// help functions
private:
//	BOOL DeleteSubItems(HTREEITEM hItem);

//
// hscroll the control
//
public:
	void GetHPosInfo(DWORD* pdwCurPos, DWORD* pdwMax=NULL);
	BOOL SetHPos(DWORD dwCurPos);

//
// Hit test
public:
	HTREEITEM HitTest(CPoint pt, UINT* pFlags = NULL, DWORD* pdwSubId=NULL);
private:
	HTREEITEM MCTHitTest(CPoint* pcPt, DWORD* pdwSubId, RECT* pSubRc=NULL);

//
// edit subitem
private:
	enum enCMCTEditCtrl{CMCT_EDIT=1};
	void BeginEdit(CRect* pcRect);
	void EndEdit();
	void UpdateSubCtrls();
	LRESULT SendEditNotify(UINT message, LPCTSTR lpszString);


private:
	DWORD CacClmnWdth();

///////////////////////////////////////////////
//
// type defines and members
//
private:

	//
	// mctree item
	class CMCTreeItem
	{
	public:
		CMCTreeItem(DWORD dwDim, DWORD_PTR dwPara=NULL):m_vStr(dwDim), m_dwPara(dwPara)
		{};
		~CMCTreeItem()
		{};
	public:
		DWORD_PTR m_dwPara;					// user special
		std::vector<CString> m_vStr;
	};

	//
	// mctree column
	class CTreeClmn
	{
	public:
		CTreeClmn(WORD wWidth=0, WORD wId=0, DWORD dwFlag=0)
			:m_wWidth(wWidth),m_wId(wId), m_dwFlag(dwFlag){}

	public:
		WORD m_wWidth;
		WORD m_wId;			// note id=0 is used for the tree control dedicated
		DWORD m_dwFlag;		// some flag about the column. now support editable
	};

private:
	//item property
	DWORD m_dwDimension;

	// columns
	std::vector<CTreeClmn> m_vcClmn;
	DWORD m_dwWidth;		// total length

	// 
	int m_iXoff;

	// edit
	CInPlcEdit* m_pcEdit;
	CMCTreeItem* m_pEditItem;
	HTREEITEM m_hEditItem;
	WORD m_wEditSubId;

	// capture mouse when selected
	BOOL m_fCaptured;
};
